#include "OperandDisplay.h"

#include <QBoxLayout>
#include <QLabel>
#include <QSpinBox>
#include <QRadioButton>
#include <QButtonGroup>
#include <QGroupBox>
#include <QGroupBox>
#include <QComboBox>

#define UPDATE_MASK_NONE  0
#define UPDATE_MASK_BIN   1
#define UPDATE_MASK_HEX   2
#define UPDATE_MASK_DEC   4
#define UPDATE_MASK_ASCII 8
#define UPDATE_MASK_BIT   16
#define UPDATE_MASK_SIZE  32


OperandDisplay::OperandDisplay(QWidget *parent, bool editable) :
    QWidget(parent), mEditable(editable)
{
    array = new BitArray(32, false);
    binDisplay = new ArrayBinEditor(array, editable, this);
    hexDisplay = new ArrayHexEditor(array, editable, this);
    dezDisplay = new ArrayDecEditor(array, editable, this);
    ascDisplay = new ArrayAsciiEditor(array, editable, this);
    mCBoxDisplay = new BitEditor(array, editable, this);
    sizeEditor = new ArraySizeEditor(array, editable, this);
    opWidget = new UnaryOpWidget(array);

    cBoxSigned  = new QCheckBox("Signed");
    cBoxBEndian = new QCheckBox("Big Endian");

    chkBoxShowSep = new QCheckBox("Separator");
    chkBoxShowSep->setChecked(false);

    QVBoxLayout *vLayout0 = new QVBoxLayout(this);
    QVBoxLayout *vLayout1 = new QVBoxLayout();
    QVBoxLayout *vLayout2 = new QVBoxLayout();
    QVBoxLayout *vLayout3 = new QVBoxLayout();

    QHBoxLayout *hLayout0 = new QHBoxLayout();
    QHBoxLayout *hLayout1 = new QHBoxLayout();
    QHBoxLayout *hLayout2 = new QHBoxLayout();

    QGridLayout *gLayout = new QGridLayout();

    vLayout0->setContentsMargins(0, 0, 0, 0);
    vLayout1->setContentsMargins(0, 0, 0, 0);
    vLayout2->setContentsMargins(0, 0, 0, 0);
    vLayout3->setContentsMargins(0, 0, 0, 0);
    hLayout0->setContentsMargins(0, 0, 0, 0);
    hLayout1->setContentsMargins(0, 0, 0, 0);
    hLayout2->setContentsMargins(0, 0, 0, 0);
    gLayout->setContentsMargins(0, 0, 0, 0);

    hLayout2->addWidget(new QLabel("BIN:"));
    hLayout2->addWidget(binDisplay->widget());

    gLayout->addWidget(new QLabel("HEX:"), 1, 0);
    gLayout->addWidget(hexDisplay->widget(), 1, 1);
    gLayout->addWidget(new QLabel("DEC:"), 2, 0);
    gLayout->addWidget(dezDisplay->widget(), 2, 1);
    gLayout->addWidget(new QLabel("ASCII:"), 3, 0);
    gLayout->addWidget(ascDisplay->widget(), 3, 1);
    gLayout->setVerticalSpacing(0);

    QGroupBox *intprBox = new QGroupBox("Interpretation", this);
    QVBoxLayout *intprBoxLayout = new QVBoxLayout(intprBox);
    intprBoxLayout->addWidget(cBoxSigned);
    intprBoxLayout->addWidget(cBoxBEndian);
    intprBoxLayout->setContentsMargins(5, 0, 0, 5);

    QGroupBox *cBoxBox = new QGroupBox("      Bit Editor", this);
    mPbShowCBoxDisplay = new QPushButton("+", cBoxBox);
    mPbShowCBoxDisplay->resize(20, 20);
    QVBoxLayout *cBoxBoxLayout = new QVBoxLayout(cBoxBox);
    cBoxBoxLayout->addWidget(mCBoxDisplay);
    mCBoxDisplay->hide();

    vLayout3->addWidget(sizeEditor->widget());
    vLayout3->addWidget(intprBox);

    vLayout2->addWidget(opWidget);
    vLayout2->insertStretch(-1);

    hLayout1->addLayout(gLayout);
    hLayout1->addLayout(vLayout2);

    vLayout1->addLayout(hLayout2);
    vLayout1->addLayout(hLayout1);

    hLayout0->addLayout(vLayout1);
    hLayout0->addLayout(vLayout3);

    vLayout0->addLayout(hLayout0);
    vLayout0->addWidget(cBoxBox);

    if(!editable)
    {
        opWidget->hide();
    }

    updateView(UPDATE_MASK_NONE);

    connect(binDisplay, SIGNAL(valueChanged()), this, SLOT(binValChanged()));
    connect(hexDisplay, SIGNAL(valueChanged()), this, SLOT(hexValChanged()));
    connect(dezDisplay, SIGNAL(valueChanged()), this, SLOT(dezValChanged()));
    connect(ascDisplay, SIGNAL(valueChanged()), this, SLOT(ascValChanged()));

    connect(mCBoxDisplay, SIGNAL(valueChanged()), this, SLOT(cBoxValChanged()));
    connect(sizeEditor, SIGNAL(valueChanged()), this, SLOT(sizeValChanged()));
    connect(cBoxSigned, SIGNAL(clicked()), this, SLOT(signChanged()));
    connect(cBoxBEndian, SIGNAL(clicked()), this, SLOT(endianChanged()));
    connect(opWidget, SIGNAL(operationExec(BitArray)), this, SLOT(operationExecSlot(BitArray)));
    connect(mPbShowCBoxDisplay, SIGNAL(clicked()), this, SLOT(showHideCBoxDisplay()));

}

void OperandDisplay::updateView(int updateMask)
{
    if(updateMask != UPDATE_MASK_BIN)
        binDisplay->updateView();
    if(updateMask != UPDATE_MASK_HEX)
        hexDisplay->updateView();
    if(updateMask != UPDATE_MASK_DEC)
        dezDisplay->updateView();
    if(updateMask != UPDATE_MASK_ASCII)
        ascDisplay->updateView();
    if(updateMask != UPDATE_MASK_BIT)
        mCBoxDisplay->updateView();
    if(updateMask != UPDATE_MASK_SIZE)
        sizeEditor->updateView();
}

void OperandDisplay::binValChanged()
{
    updateView(UPDATE_MASK_BIN);
    emit valueChanged();
}

void OperandDisplay::hexValChanged()
{
    updateView(UPDATE_MASK_HEX);
    emit valueChanged();
}

void OperandDisplay::dezValChanged()
{
    updateView(UPDATE_MASK_DEC);
    emit valueChanged();
}

void OperandDisplay::ascValChanged()
{
    updateView(UPDATE_MASK_ASCII);
    emit valueChanged();
}

void OperandDisplay::cBoxValChanged()
{
    updateView(UPDATE_MASK_BIT);
    emit valueChanged();
}

void OperandDisplay::sizeValChanged()
{
    updateView(UPDATE_MASK_SIZE);
    emit valueChanged();
}


void OperandDisplay::signChanged()
{
    array->setSigned(cBoxSigned->isChecked());
    updateView(UPDATE_MASK_NONE);
}

void OperandDisplay::endianChanged()
{
    array->setBEndian(cBoxBEndian->isChecked());
    updateView(UPDATE_MASK_NONE);
}

void OperandDisplay::operationExecSlot(BitArray ba)
{
    (*array) = ba;
    opWidget->setArray(array);
    updateView(UPDATE_MASK_NONE);
    emit valueChanged();
}

void OperandDisplay::showHideCBoxDisplay()
{
    if(mCBoxDisplay->isVisible())
    {
        mCBoxDisplay->hide();
        mPbShowCBoxDisplay->setText("+");
    }
    else
    {
        mCBoxDisplay->show();
        mCBoxDisplay->updateView();
        mPbShowCBoxDisplay->setText("-");
    }
}

